package com.jzy.controller;

import com.jzy.constant.WebConstant;
import com.jzy.dto.ErrorCode;
import com.jzy.dto.Types;
import com.jzy.entity.Bo.RestResponseBo;
import com.jzy.entity.Vo.CommentVo;
import com.jzy.entity.Vo.ContentVo;
import com.jzy.exception.TipException;
import com.jzy.service.ICommentService;
import com.jzy.service.IContentService;
import com.jzy.util.IpKit;
import com.jzy.util.PageUtil;
import com.jzy.util.PatternKit;
import com.jzy.util.TaleUtils;
import com.vdurmont.emoji.EmojiParser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


/**
 * 首页
 */
@Controller
public class IndexController extends BaseController{

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexController.class);

    @Resource
    private IContentService contentService;

    @Resource
    private ICommentService commentService;

    /**
     * 首页
     * @return
     */
    @GetMapping(value = {"/", "index"})
    public String toIndex(Model model, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        return this.index(model, 1, limit);
    }

    /**
     * 首页分页
     *
     * @param model   model
     * @param p       第几页
     * @param limit   每页大小
     * @return 主页
     */
    @GetMapping(value = "page/{p}")
    public String index(Model model, @PathVariable int p, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        p = p < 0 || p > WebConstant.MAX_PAGE ? 1 : p;
        Page<ContentVo> articles = contentService.getContents(p, limit);
        long totalElements = articles.getTotalElements();
        PageUtil pageUtil = new PageUtil(p, limit, (int) totalElements);
        model.addAttribute("articles", articles.getContent());
        model.addAttribute("pageUtil", pageUtil);
        if (p > 1) {
            this.title(model, "第" + p + "页");
        }
        return this.render("index");
    }

    /**
     * 文章页
     *
     * @param request 请求
     * @param cid     文章主键
     * @return
     */
    @GetMapping(value = {"article/{cid}", "article/{cid}.html"})
    public String getArticle(Model model, HttpServletRequest request, @PathVariable String cid) {
        ContentVo contents = contentService.getContents(cid);
        if (null == contents || "draft".equals(contents.getStatus())) {
            return this.render_404();
        }
        model.addAttribute("article", contents);
        model.addAttribute("is_post", true);
        completeArticle(request, contents);
        /*和查找文章 更新点击率重复 使用缓存更新可以降低数据库的压力*/
//        updateArticleHit(contents.getCid(), contents.getHits());
        return this.render("post");
    }

    /**
     * 抽取公共方法
     *
     * @param request
     * @param contents
     */
    private void completeArticle(HttpServletRequest request, ContentVo contents) {
        if (contents.getAllowComment()) {
            String cp = request.getParameter("cp");
            if (StringUtils.isBlank(cp)) {
                cp = "1";
            }
            request.setAttribute("cp", cp);
            Page<CommentVo> commentsPaginator = commentService.getComments(contents.getCid(), Integer.parseInt(cp), 6);
            long totalElements = commentsPaginator.getTotalElements();
            PageUtil pageUtil = new PageUtil(Integer.parseInt(cp), 6, (int) totalElements);
            request.setAttribute("comments", commentsPaginator.getContent());
            request.setAttribute("pageUtil", pageUtil);
        }
    }

    /**
     * 更新文章的点击率
     *
     * @param cid
     * @param chits
     */
    @Transactional(rollbackFor = TipException.class)
    void updateArticleHit(Integer cid, Integer chits) {
        Integer hits = cache.hget("article", "hits");
        if (chits == null) {
            chits = 0;
        }
        hits = null == hits ? 1 : hits + 1;
        if (hits >= WebConstant.HIT_EXCEED) {
            ContentVo temp = new ContentVo();
            temp.setCid(cid);
            temp.setHits(chits + hits);
            contentService.updateContentByCid(temp);
            cache.hSet("article", "hits", 1);
        } else {
            cache.hSet("article", "hits", hits);
        }
    }

    /**
     * 评论操作
     */
    @PostMapping(value = "comment")
    @ResponseBody
    @Transactional(rollbackFor = TipException.class)
    public RestResponseBo comment(CommentVo commentVo, HttpServletRequest request, HttpServletResponse response ,@RequestParam String _csrf_token) throws UnsupportedEncodingException {
        String ref = request.getHeader("Referer");
        if (StringUtils.isBlank(ref) || StringUtils.isBlank(_csrf_token)) {
            return RestResponseBo.fail(ErrorCode.BAD_REQUEST);
        }
        String token = cache.hget(Types.CSRF_TOKEN.getType(), _csrf_token);
        if (StringUtils.isBlank(token)) {
            return RestResponseBo.fail(ErrorCode.BAD_REQUEST);
        }
        if (null == commentVo.getCid() || StringUtils.isBlank(commentVo.getContent())) {
            return RestResponseBo.fail("请输入完整后评论");
        }
        if (StringUtils.isNotBlank(commentVo.getAuthor()) && commentVo.getAuthor().length() > 50) {
            return RestResponseBo.fail("姓名过长");
        }
        if (StringUtils.isNotBlank(commentVo.getMail()) && !TaleUtils.isEmail(commentVo.getMail())) {
            return RestResponseBo.fail("请输入正确的邮箱格式");
        }

        if (StringUtils.isNotBlank(commentVo.getUrl()) && !PatternKit.isURL(commentVo.getUrl())) {
            return RestResponseBo.fail("请输入正确的URL格式");
        }
        if (commentVo.getContent().length() > 200) {
            return RestResponseBo.fail("请输入200个字符以内的评论");
        }
        String val = IpKit.getIpAddrByRequest(request) + ":" + commentVo.getCid();
        Integer count = cache.hget(Types.COMMENTS_FREQUENCY.getType(), val);
        if (null != count && count > 0) {
            return RestResponseBo.fail("您发表评论太快了，请过会再试");
        }
        commentVo.setAuthor(EmojiParser.parseToAliases(TaleUtils.cleanXSS(commentVo.getAuthor())));
        commentVo.setContent(EmojiParser.parseToAliases(TaleUtils.cleanXSS(commentVo.getContent())));
        commentVo.setIp(request.getRemoteAddr());
        commentVo.setParent(commentVo.getCoid());
        commentService.insertComment(commentVo);
        cookie("tale_remember_author", URLEncoder.encode(commentVo.getAuthor(), "UTF-8"), 7 * 24 * 60 * 60, response);
        cookie("tale_remember_mail", URLEncoder.encode(commentVo.getMail(), "UTF-8"), 7 * 24 * 60 * 60, response);
        if (StringUtils.isNotBlank(commentVo.getUrl())) {
            cookie("tale_remember_url", URLEncoder.encode(commentVo.getUrl(), "UTF-8"), 7 * 24 * 60 * 60, response);
        }
        // 设置对每个文章1分钟可以评论一次
        cache.hSet(Types.COMMENTS_FREQUENCY.getType(), val, 1, 60);
        return RestResponseBo.ok();
    }

    /**
     * 设置cookie
     *
     * @param name
     * @param value
     * @param maxAge
     * @param response
     */
    private void cookie(String name, String value, int maxAge, HttpServletResponse response) {
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(maxAge);
        cookie.setSecure(false);
        response.addCookie(cookie);
    }
}
